package cn.edu.gdu.quizpractice.common.utils;

/**
 * @Author: Aubery
 * @Date: 2025-01-28-13:30
 * @Description:
 */

import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.security.Key;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;

@Component
public class JwtUtils {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;

    public String generateToken(UserDetails userDetails) {
        String token = Jwts.builder()
                .setSubject(userDetails.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(getSigningKey(), SignatureAlgorithm.HS256)
                .compact();
        
        System.out.println("生成的Token: " + token);
        
        // 检查Redis中是否已有token
        String existingToken = redisTemplate.opsForValue().get(userDetails.getUsername());
        System.out.println("Redis中已有的Token: " + existingToken);
        
        // 确保只存储新token
        redisTemplate.opsForValue().set(
            userDetails.getUsername(), 
            token, // 不要与现有token拼接
            expiration, 
            java.util.concurrent.TimeUnit.MILLISECONDS
        );
        
        return token;
    }

    /**
     * 从token中提取用户名
     * @param token JWT token
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        try {
            // System.out.println("原始 Token: " + token);
            
            // 检查是否是Authorization头
            if (token != null && token.startsWith("Bearer ")) {
                token = token.substring(7);
                System.out.println("从Authorization头中提取Token: " + token);
            }
            
            // 处理可能的逗号分隔情况
            if (token.contains(",")) {
                token = token.split(",")[0]; // 只取第一部分
            }
            
            // 检查token格式
            int dots = 0;
            for (char c : token.toCharArray()) {
                if (c == '.') dots++;
            }

            // 使用签名密钥解析Token
            Jws<Claims> claimsJws = Jwts.parserBuilder()
                .setSigningKey(getSigningKey())
                .build()
                .parseClaimsJws(token);

            // 从Claims中获取用户名（存储在Subject中）
            Claims claims = claimsJws.getBody();
            return claims.getSubject();
        } catch (JwtException e) {
            System.err.println("JWT解析错误: " + e.getMessage());
            throw new IllegalArgumentException("Invalid token: " + e.getMessage());
        }
    }

    private Key getSigningKey() {
        byte[] keyBytes = Decoders.BASE64.decode(secret);
        return Keys.hmacShaKeyFor(keyBytes);
    }


    public boolean validateToken(String token, UserDetails userDetails) {
        try {
            String username = getUsernameFromToken(token);
            return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
        } catch (Exception e) {
            System.out.println("Token验证失败: " + e.getMessage());
            return false;
        }
    }

    private boolean isTokenExpired(String token) {
        return Jwts.parserBuilder()
            .setSigningKey(getSigningKey())
            .build()
            .parseClaimsJws(token)
            .getBody()
            .getExpiration()
            .before(new Date());
    }




    // 根据用户ID生成token的方法
    public String generateTokenByUserId(Long userId) {
        return generateToken(new UserDetailsAdapter(userId.toString()));
    }

    // 用户详情适配器
    private static class UserDetailsAdapter implements UserDetails {
        private final String username;

        public UserDetailsAdapter(String username) {
            this.username = username;
        }

        @Override public String getUsername() { return username; }
        @Override public String getPassword() { return ""; }
        @Override public Collection<? extends GrantedAuthority> getAuthorities() { return Collections.emptyList(); }
        @Override public boolean isAccountNonExpired() { return true; }
        @Override public boolean isAccountNonLocked() { return true; }
        @Override public boolean isCredentialsNonExpired() { return true; }
        @Override public boolean isEnabled() { return true; }
    }

}
